package net.xdclass.service.impl;

import com.alibaba.fastjson.JSON;
import lombok.extern.slf4j.Slf4j;
import net.xdclass.constant.CacheKey;
import net.xdclass.enums.BizCodeEnum;
import net.xdclass.exception.BizException;
import net.xdclass.interceptor.LoginInterceptor;
import net.xdclass.model.LoginUser;
import net.xdclass.request.CartItemRequest;
import net.xdclass.service.CartService;
import net.xdclass.service.ProductService;
import net.xdclass.vo.CartItemVO;
import net.xdclass.vo.CartVO;
import net.xdclass.vo.ProductVO;
import org.apache.commons.lang3.StringUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.data.redis.core.BoundHashOperations;
import org.springframework.data.redis.core.RedisTemplate;
import org.springframework.stereotype.Service;

import java.util.ArrayList;
import java.util.List;
import java.util.Map;
import java.util.function.Function;
import java.util.stream.Collectors;

@Service
@Slf4j
public class CartServiceImpl implements CartService {
    @Autowired
    private RedisTemplate redisTemplate;

    @Autowired
    private ProductService productService;

    @Override
    public CartVO getMyCart() {
        CartVO cartVO = new CartVO();
        cartVO.setCartItems(buildCartItem(false));
        return cartVO;
    }

    private List<CartItemVO> buildCartItem(boolean latestPrice) {
        BoundHashOperations<String, Object, Object> myCart = getMyCartOps();
        List<Object> itemList = myCart.values();
        List<Long> productIdList = new ArrayList<>();
        List<CartItemVO> cartItemVOList = itemList.stream()
                .map(item -> {
                    CartItemVO cartItemVO = JSON.parseObject((String)item, CartItemVO.class);
                    productIdList.add(cartItemVO.getProductId());
                    return cartItemVO;
                })
                .collect(Collectors.toList());

        if (latestPrice) {
            setProductLatestPrice(cartItemVOList, productIdList);
        }

        return cartItemVOList;
    }

    private void setProductLatestPrice(List<CartItemVO> cartItemVOList, List<Long> productIdList) {
        List<ProductVO> productVOList = productService.findProductsByIdBatch(productIdList);
        Map<Long, ProductVO> maps = productVOList.stream()
                .collect(Collectors.toMap(ProductVO::getId, Function.identity()));

        cartItemVOList.stream().forEach(item -> {
            ProductVO productVO = maps.get(item.getProductId());
            item.setProductTitle(productVO.getTitle());
            item.setProductImg(productVO.getCoverImg());
            item.setAmount(productVO.getAmount());
        });
    }

    @Override
    public void addToCart(CartItemRequest cartItemRequest) {
        long productId = cartItemRequest.getProductId();
        int buyNum = cartItemRequest.getBuyNum();

        BoundHashOperations<String, Object, Object> myCart = getMyCartOps();
        Object cacheObj = myCart.get(productId);
        String result = "";

        if (cacheObj != null) {
            result = (String)cacheObj;
        }

        if (StringUtils.isBlank(result)) {
            CartItemVO cartItemVO = new CartItemVO();
            ProductVO productVO = productService.detail(productId);
            if (productVO == null) throw new BizException(BizCodeEnum.CART_FAIL);

            cartItemVO.setAmount(productVO.getAmount());
            cartItemVO.setBuyNum(buyNum);
            cartItemVO.setProductId(productId);
            cartItemVO.setProductImg(productVO.getCoverImg());
            cartItemVO.setProductTitle(productVO.getTitle());

            myCart.put(productId, JSON.toJSONString(cartItemVO));
        } else {
            CartItemVO cartItem = JSON.parseObject(result, CartItemVO.class);
            cartItem.setBuyNum(cartItem.getBuyNum() + buyNum);
            myCart.put(productId, JSON.toJSONString(cartItem));
        }

    }

    @Override
    public void clear() {
        String cartKey = getCacheKey();
        redisTemplate.delete(cartKey);
    }

    @Override
    public void deleteItem(long productId) {
        BoundHashOperations<String, Object, Object> cart = getMyCartOps();
        cart.delete(productId);
    }

    @Override
    public void changeItemNum(CartItemRequest cartItemRequest) {
        BoundHashOperations<String, Object, Object> myCart = getMyCartOps();
        Object cacheObj = myCart.get(cartItemRequest.getProductId());
        if (cacheObj == null) throw new BizException(BizCodeEnum.CART_FAIL);
        String result = (String)cacheObj;
        CartItemVO cartItemVO = JSON.parseObject(result, CartItemVO.class);
        cartItemVO.setBuyNum(cartItemRequest.getBuyNum());
        myCart.put(cartItemRequest.getProductId(), JSON.toJSONString(cartItemVO));
    }

    private BoundHashOperations<String, Object, Object> getMyCartOps() {
        String cartKey = getCacheKey();
        return redisTemplate.boundHashOps(cartKey);
    }

    private String getCacheKey() {
        LoginUser loginUser = (LoginUser)LoginInterceptor.threadLocal.get();
        String cartKey = String.format(CacheKey.CART_KEY, loginUser.getId());
        return cartKey;
    }

    @Override
    public List<CartItemVO> confirmOrderCartItems(List<Long> productIdList) {
        List<CartItemVO> cartItemVOList = buildCartItem(true);
        List<CartItemVO> resultList = cartItemVOList.stream().filter(obj -> {
           if (productIdList.contains(obj)) {
               this.deleteItem(obj.getProductId());
               return true;
           }
           return false;
        }).collect(Collectors.toList());

        return resultList;
    }
}
